﻿using StackExchange.Redis;
using System;
using System.Linq;


namespace Cxuu.Common
{
    //知识点：Redis hash 是一个 string 类型的 field 和 value 的映射表，hash 特别适合用于存储对象。
    public class RedisCacheManager : ICacheManager
    {
        private readonly string cacheMainName = Appsettings.App(new string[] { "AppSettings", "SystemName" }) + ".";// "CxuuWeb.";
        private readonly string redisConnenctionString;
        public volatile ConnectionMultiplexer redisConnection;
        private readonly object redisConnectionLock = new();
        public RedisCacheManager()
        {
            string redisConfiguration = Appsettings.App(new string[] { "RedisCaching", "ConnectionString" });//获取连接字符串

            if (string.IsNullOrWhiteSpace(redisConfiguration))
            {
                throw new ArgumentException("redis config is empty", nameof(redisConfiguration));
            }
            this.redisConnenctionString = redisConfiguration;
            this.redisConnection = GetRedisConnection();
        }

        /// <summary>
        /// 核心代码，获取连接实例
        /// 通过双if 加lock的方式，实现单例模式
        /// </summary>
        /// <returns></returns>
        private ConnectionMultiplexer GetRedisConnection()
        {
            //如果已经连接实例，直接返回
            if (this.redisConnection != null && this.redisConnection.IsConnected)
            {
                return this.redisConnection;
            }
            //加锁，防止异步编程中，出现单例无效的问题
            lock (redisConnectionLock)
            {
                if (this.redisConnection != null)
                {
                    //释放redis连接
                    this.redisConnection.Dispose();
                }
                try
                {
                    this.redisConnection = ConnectionMultiplexer.Connect(redisConnenctionString);
                }
                catch (Exception)
                {
                    throw new Exception("Redis服务未启用，请开启该服务");
                }
            }
            return this.redisConnection;
        }

        /// <summary>
        /// 数据如有更改，删除指定缓存
        /// </summary>
        /// <returns></returns>
        public void Remove(string cacheKey)
        {
            if (Exists(cacheMainName + cacheKey) == true)
            {
                redisConnection.GetDatabase().KeyDelete(cacheMainName + cacheKey); ;
            }
        }

        public long TotalNumber()
        {
            var endPoint = redisConnection.GetEndPoints().FirstOrDefault();
            var server = redisConnection.GetServer(endPoint);
            return server.DatabaseSize();
        }
        /// <summary>
        /// //获取 缓存 的KEY VALUE SIZE等信息
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        //public (List<ViewCacheModel> redisList, long total) GetRedisModels(int page, int limit)
        //{
        //    List<ViewCacheModel> models = new();
        //    //List<ViewRedisAll> viewRedis = new();
        //    var endPoint = redisConnection.GetEndPoints().FirstOrDefault();

        //    //获取指定服务器
        //    var server = redisConnection.GetServer(endPoint);
        //    long totalNumber = server.DatabaseSize();
        //    //在指定服务器上使用 keys 或者 scan 命令来遍历key 只支持Keys   cacheName + 
        //    var keyList = server.Keys(-1, "*", limit, page * limit);
        //    foreach (var key in keyList)
        //    {
        //     long size = redisConnection.GetDatabase().StringBitCount(key);
        //        //var val = redisConnection.GetDatabase().StringGet(key);
        //        models.Add(new ViewCacheModel { Key = key, Size = size });
        //    }
        //    //viewRedis.Add( new ViewRedisAll { ListAll = models,Total = totalNumber });
        //    return (models, totalNumber);
        //}

        /// <summary>
        /// 清除所有本项目缓存
        /// </summary>
        /// <returns></returns>
        public bool Clear()
        {
            try
            {
                foreach (var endPoint in this.GetRedisConnection().GetEndPoints())
                {
                    var server = this.GetRedisConnection().GetServer(endPoint);
                    foreach (var key in server.Keys(-1, cacheMainName + "*"))
                    {
                        redisConnection.GetDatabase().KeyDelete(key);
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool Exists(string key)
        {
            return redisConnection.GetDatabase().KeyExists(cacheMainName + key);
        }

        public string GetValue(string key)
        {
            return redisConnection.GetDatabase().StringGet(cacheMainName + key);
        }

        public TEntity Get<TEntity>(string key)
        {
            var value = redisConnection.GetDatabase().StringGet(cacheMainName + key);
            if (value.HasValue)
            {
                //需要用的反序列化，将Redis存储的Byte[]，进行反序列化
                return SerializeUtility.Deserialize<TEntity>(value);
            }
            else
            {
                return default;
            }
        }

        

        public void Set(string key, object value, TimeSpan cacheTime)
        {
            if (value != null)
            {
                //序列化，将object值生成RedisValue
                redisConnection.GetDatabase().StringSet(cacheMainName + key, SerializeUtility.Serialize(value), cacheTime);
            }
        }

    }
}
